package com.yc.music.service;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.LocalRemoteObject;
import ohos.aafwk.content.Intent;
import ohos.aafwk.content.Operation;
import ohos.event.commonevent.CommonEventManager;
import ohos.event.commonevent.CommonEventSubscribeInfo;
import ohos.event.commonevent.CommonEventSupport;
import ohos.event.commonevent.MatchingSkills;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.media.common.Source;
import ohos.media.player.Player;
import ohos.rpc.IRemoteObject;
import ohos.rpc.RemoteException;

import com.yc.music.config.MusicConstant;
import com.yc.music.config.MusicPlayAction;
import com.yc.music.config.PlayModeEnum;
import com.yc.music.inter.EventCallback;
import com.yc.music.inter.OnPlayerEventListener;
import com.yc.music.manager.AudioFocusManager;
import com.yc.music.manager.MediaSessionManager;
import com.yc.music.model.AudioBean;
import com.yc.music.receiver.AudioBroadcastReceiver;
import com.yc.music.receiver.AudioEarPhoneReceiver;
import com.yc.music.tool.BaseAppHelper;
import com.yc.music.tool.QuitTimerHelper;
import com.yc.music.utils.MusicLogUtils;
import com.yc.music.utils.MusicSpUtils;
import com.yc.music.utils.NotificationManager;

import java.security.SecureRandom;
import java.util.List;

/**
 * Service就是用来在后台完成一些不需要和用户交互的动作
 *
 * @since 2021-05-10
 */
public class PlayService extends Ability {
    /**
     * 更新播放进度的显示，时间的显示
     */
    private static final int UPDATE_PLAY_PROGRESS_SHOW = 0;
    /**
     * 正在播放的歌曲的序号
     */
    private int mPlayingPosition = -1;
    /**
     * 正在播放的歌曲[本地|网络]
     */
    private AudioBean mPlayingMusic;
    /**
     * 音频list集合
     */
    private List<AudioBean> audioMusics;
    /**
     * 播放状态
     */
    private int mPlayState = MusicPlayAction.STATE_IDLE;
    /**
     * 播放器
     */
    private Player mPlayer;
    /**
     * 播放进度监听器
     */
    private OnPlayerEventListener mListener;
    /**
     * 允许与媒体控制器、音量键、媒体按钮和传输控件交互
     */
    private MediaSessionManager mMediaSessionManager;
    /**
     * 捕获/丢弃音乐焦点处理
     */
    private AudioFocusManager mAudioFocusManager;
    /**
     * 是否锁屏了，默认是false
     */
    private boolean mIsLocked = false;
    /**
     * 来电/耳机拔出时暂停播放
     * 在播放时调用，在暂停时注销
     */
    private AudioEarPhoneReceiver mNoisyReceiver;
    /**
     * 其他广播
     * 比如：屏幕灭了后再次亮了，会显示锁屏页面
     * 这个在onCreate中创建，在onDestroy中销毁
     */
    private AudioBroadcastReceiver mAudioReceiver;
    /**
     * 广播接受者标识，避免多次注册广播
     */
    private boolean isReceiverTag = false;

    private EventHandler handler = new EventHandler(EventRunner.getMainEventRunner()) {
        @Override
        protected void processEvent(InnerEvent event) {
            super.processEvent(event);
            switch (event.eventId) {
                case UPDATE_PLAY_PROGRESS_SHOW:
                    updatePlayProgressShow();
                    break;
                default:
                    break;
            }
        }
    };
    // 音频准备好的监听器
    private Player.IPlayerCallback mOnPreparedListener = new Player.IPlayerCallback() {
        /**
         * 当音频准备好可以播放了，则这个方法会被调用
         */
        @Override
        public void onPrepared() {
            if (isPreparing()) {
                start();
            }
        }

        @Override
        public void onMessage(int i, int i1) {
            return;
        }

        @Override
        public void onError(int i, int i1) {
            return;
        }

        @Override
        public void onResolutionChanged(int i, int i1) {
        }

        /**
         * 当音频播放结束的时候的监听器
         */
        @Override
        public void onPlayBackComplete() {
            next();
        }

        @Override
        public void onRewindToComplete() {
        }

        /**
         * 当音频缓冲的监听器
         *
         * @param percent percent
         */
        @Override
        public void onBufferingChange(int percent) {
            if (mListener != null) {
                // 缓冲百分比
                mListener.onBufferingUpdate(percent);
            }
        }

        @Override
        public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
        }

        @Override
        public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
        }
    };

    /**
     * 绑定服务时才会调用
     * 必须要实现的方法
     *
     * @param intent intent
     * @return IRemoteObject对象
     */
    @Override
    public IRemoteObject onConnect(Intent intent) {
        return new PlayBinder();
    }

    /**
     * 比如，广播，耳机声控，通知栏广播，来电或者拔下耳机广播开启服务
     *
     * @param type 类型
     */
    public void startCommand(String type) {
        Intent intent = new Intent();
        Operation operation = new Intent.OperationBuilder()
            .withDeviceId("")
            .withBundleName("org.yczbj.ycvideoplayer")
            .withAbilityName("com.yc.music.service.PlayService")
            .build();
        intent.setOperation(operation);
        intent.setType(type);
        startAbility(intent);
    }

    /**
     * PlayBinder
     *
     * @since 2021-05-10
     */
    public class PlayBinder extends LocalRemoteObject {
        /**
         * getService
         *
         * @return PlayService
         */
        public PlayService getService() {
            return PlayService.this;
        }
    }

    /**
     * 首次创建服务时，系统将调用此方法来执行一次性设置程序（在调用 onStartCommand() 或 onBind() 之前）。
     * 如果服务已在运行，则不会调用此方法。该方法只被调用一次
     *
     * @param intent intent
     */
    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        NotificationManager.get().init(this);
        createMediaPlayer();
        initMediaSessionManager();
        initAudioFocusManager();
        initEarPhoneBroadcastReceiver();
        initAudioBroadcastReceiver();
        initQuitTimer();
    }

    /**
     * 服务在销毁时调用该方法
     */
    @Override
    public void onStop() {
        super.onStop();

        // 销毁handler
        if (handler != null) {
            handler.removeTask(null);
            handler = null;
        }

        // 销毁MediaPlayer
        mPlayer.reset();
        mPlayer.release();
        mPlayer = null;

        // 放弃音频焦点
        mAudioFocusManager.abandonAudioFocus();
        mMediaSessionManager.release();

        // 注销广播接收者
        try {
            CommonEventManager.unsubscribeCommonEvent(mAudioReceiver);
        } catch (RemoteException e) {
            MusicLogUtils.e(e.getMessage());
        }

        // 结束notification通知
        NotificationManager.get().cancelAll();

        // 设置service为null
        BaseAppHelper.get().setPlayService(null);
    }

    /**
     * 每次通过startService()方法启动Service时都会被回调。
     *
     * @param intent intent
     * @param isRestart isRestart
     * @param startId startId
     * START_STICKY：粘性，service进程被异常杀掉，系统重新创建进程与服务，会重新执行onCreate()、onStartCommand(Intent)
     * START_STICKY_COMPATIBILITY：START_STICKY的兼容版本，但不保证服务被kill后一定能重启。
     * START_NOT_STICKY：非粘性，Service进程被异常杀掉，系统不会自动重启该Service。
     * START_REDELIVER_INTENT：重传Intent。使用这个返回值时，如果在执行完onStartCommand后，服务被异常kill掉，系统会自动重启该服务，并将Intent的值传入。
     */
    @Override
    protected void onCommand(Intent intent, boolean isRestart, int startId) {
        super.onCommand(intent, isRestart, startId);
        if (intent != null && intent.getAction() != null) {
            switch (intent.getAction()) {
                // 上一首
                case MusicPlayAction.TYPE_PRE:
                    prev();
                    break;

                // 下一首
                case MusicPlayAction.TYPE_NEXT:
                    next();
                    break;

                // 播放或暂停
                case MusicPlayAction.TYPE_START_PAUSE:
                    playPause();
                    break;

                // 添加锁屏界面
                case MusicConstant.LOCK_SCREEN_ACTION:
                    MusicLogUtils.e("PlayService" + "---LOCK_SCREEN" + mIsLocked);
                    break;

                // 当屏幕灭了，添加锁屏页面
                case CommonEventSupport.COMMON_EVENT_SCREEN_OFF:
                    startLockAudioActivity();
                    MusicLogUtils.e("PlayService" + "---当屏幕灭了");
                    break;
                case CommonEventSupport.COMMON_EVENT_SCREEN_ON:
                    MusicLogUtils.e("PlayService" + "---当屏幕亮了");
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 创建MediaPlayer对象
     */
    private void createMediaPlayer() {
        if (mPlayer == null) {
            // MediaCodec codec = new MediaCodec()
            mPlayer = new Player(getContext());
        }
    }

    /**
     * 允许与媒体控制器、音量键、媒体按钮和传输控件交互。
     * 播放器除了播放了音乐之外什么都没做，就可以分别在任务管理、锁屏、负一屏控制我的播放器
     */
    private void initMediaSessionManager() {
        mMediaSessionManager = new MediaSessionManager(this);
    }

    /**
     * 捕获/丢弃音乐焦点处理
     */
    private void initAudioFocusManager() {
        mAudioFocusManager = new AudioFocusManager(this);
    }

    /**
     * 初始化耳机插入和拔出监听
     */
    private void initEarPhoneBroadcastReceiver() {
        // 这块直接在清单文件注册
    }

    /**
     * 初始化IntentFilter添加action意图
     * 主要是监听屏幕亮了与灭了
     */
    private void initAudioBroadcastReceiver() {
        // 来电/耳机
        MatchingSkills matchingSkills = new MatchingSkills();

        // 锁屏
        matchingSkills.addEvent(MusicConstant.LOCK_SCREEN_ACTION);

        // 当屏幕灭了
        matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_SCREEN_OFF);

        // 当屏幕亮了
        matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_SCREEN_ON);
        CommonEventSubscribeInfo commonEventSubscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
        mAudioReceiver = new AudioBroadcastReceiver(commonEventSubscribeInfo);
        try {
            CommonEventManager.subscribeCommonEvent(mAudioReceiver);
        } catch (RemoteException e) {
            MusicLogUtils.e(e.getMessage());
        }
    }

    /**
     * 初始化计时器
     */
    private void initQuitTimer() {
        QuitTimerHelper.getInstance().init(this, handler, new EventCallback<Long>() {
            @Override
            public void onEvent(Long event) {
                if (mListener != null) {
                    mListener.onTimer(event);
                }
            }
        });
    }

    /**---------------------播放或暂停，上一首，下一首-----------------------------------------*/

    /**
     * 播放或暂停
     * 逻辑：
     * 1.如果正在准备，点击则是停止播放
     * 2.如果是正在播放，点击则是暂停
     * 3.如果是暂停状态，点击则是开始播放
     * 4.其他情况是直接播放
     */
    public void playPause() {
        if (isPreparing()) {
            stop();
        } else if (isPlaying()) {
            pause();
        } else if (isPausing()) {
            start();
        } else {
            play(getPlayingPosition());
        }
    }

    /**
     * 上一首
     * 记住有播放类型，单曲循环，顺序循环，随机播放
     * 逻辑：如果不是第一首，则还有上一首；如果没有上一首，则切换到最后一首
     */
    public void prev() {
        // 建议都添加这个判断
        if (audioMusics.isEmpty()) {
            return;
        }
        int playMode = MusicSpUtils.getInstance(MusicConstant.SP_NAME).getInt(MusicConstant.PLAY_MODE, 0);
        int size = audioMusics.size();
        PlayModeEnum mode = PlayModeEnum.valueOf(playMode);
        switch (mode) {
            // 随机
            case SHUFFLE:
                mPlayingPosition = new SecureRandom().nextInt(size);
                play(mPlayingPosition);
                break;

            // 单曲
            case SINGLE:
                play(mPlayingPosition);
                break;

            // 顺序播放并且循环
            case LOOP:
            default:
                if (mPlayingPosition != 0) {
                    // 如果不是第一首，则还有上一首
                    mPlayingPosition--;
                } else {
                    // 如果没有上一首，则切换到最后一首
                    mPlayingPosition = size;
                }
                play(mPlayingPosition);
                break;
        }
    }

    /**
     * 下一首
     * 记住有播放类型，单曲循环，顺序循环，随机播放
     * 逻辑：如果不是最后一首，则还有下一首；如果是最后一首，则切换回第一首
     */
    public void next() {
        // 建议都添加这个判断
        if (audioMusics.isEmpty()) {
            return;
        }
        int playMode = MusicSpUtils.getInstance(MusicConstant.SP_NAME).getInt(MusicConstant.PLAY_MODE, 0);
        int size = audioMusics.size();
        PlayModeEnum mode = PlayModeEnum.valueOf(playMode);
        switch (mode) {
            // 随机
            case SHUFFLE:
                mPlayingPosition = new SecureRandom().nextInt(size);
                play(mPlayingPosition);
                break;

            // 单曲
            case SINGLE:
                play(mPlayingPosition);
                break;

            // 顺序播放并且循环
            case LOOP:
            default:
                if (mPlayingPosition != size - 1) {
                    // 如果不是最后一首，则还有下一首
                    mPlayingPosition++;
                } else {
                    // 如果是最后一首，则切换回第一首
                    mPlayingPosition = 0;
                }
                MusicLogUtils.e("PlayService" + "----mPlayingPosition----" + mPlayingPosition);
                play(mPlayingPosition);
                break;
        }
    }

    /**---------------------开始播放，暂停播放，停止播放等-----------------------------------------*/
    /**
     * 开始播放
     */
    public void start() {
        if (!isPreparing() && !isPausing()) {
            return;
        }
        if (mPlayingMusic == null) {
            return;
        }
        if (mAudioFocusManager.requestAudioFocus()) {
            if (mPlayer != null) {
                mPlayer.play();
                mPlayState = MusicPlayAction.STATE_PLAYING;

                // 开始发送消息，执行进度条进度更新
                handler.sendEvent(UPDATE_PLAY_PROGRESS_SHOW);
                if (mListener != null) {
                    mListener.onPlayerStart();
                }

                // 当点击播放按钮时(播放详情页面或者底部控制栏)，同步通知栏中播放按钮状态
                NotificationManager.get().showPlay(mPlayingMusic);

                // 注册监听来电/耳机拔出时暂停播放广播
                if (!isReceiverTag) {
                    isReceiverTag = true;
                    try {
                        MatchingSkills matchingSkills = new MatchingSkills();
                        CommonEventSubscribeInfo info = new CommonEventSubscribeInfo(matchingSkills);
                        mNoisyReceiver = new AudioEarPhoneReceiver(info);
                        CommonEventManager.subscribeCommonEvent(mNoisyReceiver);
                    } catch (RemoteException e) {
                        MusicLogUtils.e(e.getMessage());
                    }
                }
                mMediaSessionManager.updatePlaybackState();
            }
        }
    }

    /**
     * 暂停
     */
    public void pause() {
        if (mPlayer != null) {
            // 暂停
            mPlayer.pause();

            // 切换状态
            mPlayState = MusicPlayAction.STATE_PAUSE;

            // 移除，注意一定要移除，否则一直走更新方法
            handler.removeEvent(UPDATE_PLAY_PROGRESS_SHOW);

            // 监听
            if (mListener != null) {
                mListener.onPlayerPause();
            }

            // 当点击暂停按钮时(播放详情页面或者底部控制栏)，同步通知栏中暂停按钮状态
            NotificationManager.get().showPause(mPlayingMusic);

            // 注销监听来电/耳机拔出时暂停播放广播
            // 判断广播是否注册
            if (isReceiverTag) {
                // Tag值 赋值为false 表示该广播已被注销
                isReceiverTag = false;
                try {
                    CommonEventManager.unsubscribeCommonEvent(mNoisyReceiver);
                } catch (RemoteException e) {
                    MusicLogUtils.e(e.getMessage());
                }
            }

            mMediaSessionManager.updatePlaybackState();
        }
    }

    /**
     * 停止播放
     */
    public void stop() {
        if (isDefault()) {
            return;
        }
        pause();
        if (mPlayer != null) {
            mPlayer.reset();
            mPlayState = MusicPlayAction.STATE_IDLE;
        }
    }

    /**
     * 播放索引为position的音乐
     *
     * @param position 索引
     */
    public void play(int position) {
        audioMusics = BaseAppHelper.get().getMusicList();
        if (audioMusics.isEmpty()) {
            return;
        }
        int temp = 0;
        if (position < 0) {
            temp = audioMusics.size() - 1;
        } else if (position >= audioMusics.size()) {
            // 如果是最后一首音乐，则播放时直接播放第一首音乐
            temp = 0;
        }

        mPlayingPosition = temp;
        AudioBean music = audioMusics.get(mPlayingPosition);
        String id = music.getId();
        MusicLogUtils.e("PlayService" + "----id----" + id);

        // 保存当前播放的musicId，下次进来可以记录状态
        long musicId = Long.parseLong(id);
        MusicSpUtils.getInstance(MusicConstant.SP_NAME).put(MusicConstant.MUSIC_ID, musicId);
        play(music);
    }

    /**
     * 播放，这种是直接传音频实体类
     *
     * @param music music
     */
    public void play(AudioBean music) {
        mPlayingMusic = music;
        createMediaPlayer();
        mPlayer.reset();

        // 把音频路径传给播放器
        mPlayer.setSource(new Source(mPlayingMusic.getPath()));

        // 准备
        mPlayer.prepare();

        // 设置状态为准备中
        mPlayState = MusicPlayAction.STATE_PREPARING;

        // 监听
        mPlayer.setPlayerCallback(mOnPreparedListener);

        // 当播放的时候，需要刷新界面信息
        if (mListener != null) {
            mListener.onChange(mPlayingMusic);
        }

        // 更新通知栏
        NotificationManager.get().showPlay(mPlayingMusic);

        // 更新
        mMediaSessionManager.updateMetaData(mPlayingMusic);
        mMediaSessionManager.updatePlaybackState();
    }

    /**
     * 拖动seekBar时，调节进度
     *
     * @param progress 进度
     */
    public void seekTo(long progress) {
        // 只有当播放或者暂停的时候才允许拖动bar
        if (isPlaying() || isPausing()) {
            mPlayer.rewindTo(progress);
            if (mListener != null) {
                mListener.onUpdateProgress(progress);
            }
            mMediaSessionManager.updatePlaybackState();
        }
    }

    /**
     * 更新播放进度的显示，时间的显示
     */
    private void updatePlayProgressShow() {
        if (isPlaying() && mListener != null) {
            int currentPosition = mPlayer.getCurrentTime();
            mListener.onUpdateProgress(currentPosition);
        }
        MusicLogUtils.e("updatePlayProgressShow");

        // 每30毫秒更新一下显示的内容，注意这里时间不要太短，因为这个是一个循环
        // 经过测试，60毫秒更新一次有点卡，30毫秒最为顺畅
        handler.sendEvent(UPDATE_PLAY_PROGRESS_SHOW, 300);
    }

    /**
     * 是否正在播放
     *
     * @return true表示正在播放
     */
    public boolean isPlaying() {
        return mPlayState == MusicPlayAction.STATE_PLAYING;
    }

    /**
     * 是否暂停
     *
     * @return true表示暂停
     */
    public boolean isPausing() {
        return mPlayState == MusicPlayAction.STATE_PAUSE;
    }

    /**
     * 是否正在准备中
     *
     * @return true表示正在准备中
     */
    public boolean isPreparing() {
        return mPlayState == MusicPlayAction.STATE_PREPARING;
    }

    /**
     * 是否正在准备中
     *
     * @return true表示正在准备中
     */
    public boolean isDefault() {
        return mPlayState == MusicPlayAction.STATE_IDLE;
    }

    /**------------------------------------------------------------------------------------------*/

    /**
     * 退出时候调用
     */
    public void quit() {
        // 先停止播放
        stop();

        // 移除定时器
        QuitTimerHelper.getInstance().stop();

        // 当另一个组件（如 Activity）通过调用 startService() 请求启动服务时，系统将调用onStartCommand。
        // 一旦执行此方法，服务即会启动并可在后台无限期运行。 如果自己实现此方法，则需要在服务工作完成后，
        // 通过调用 stopSelf() 或 stopService() 来停止服务。
        terminateAbility();
    }

    /**
     * 获取正在播放的本地歌曲的序号
     *
     * @return return
     */
    public int getPlayingPosition() {
        return mPlayingPosition;
    }

    /**
     * 获取正在播放的歌曲[本地|网络]
     *
     * @return return
     */
    public AudioBean getPlayingMusic() {
        return mPlayingMusic;
    }

    /**
     * 获取播放的进度
     *
     * @return long类型值
     */
    public long getCurrentPosition() {
        if (isPlaying() || isPausing()) {
            return mPlayer.getCurrentTime();
        } else {
            return 0;
        }
    }

    /**
     * 判斷是否有上一首音頻
     *
     * @return true表示有
     */
    public boolean isHavePre() {
        if (audioMusics != null && audioMusics.size() > 0) {
            if (mPlayingPosition != 0) {
                // 如果不是第一首，则还有上一首
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 判斷是否有下一首音頻
     *
     * @return true表示有
     */
    public boolean isHaveNext() {
        if (audioMusics != null && audioMusics.size() > 0) {
            if (mPlayingPosition != audioMusics.size() - 1) {
                // 如果不是最后一首，则还有下一首
                return true;
            } else {
                // 如果是最后一首，则切换回第一首
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 删除或下载歌曲后刷新正在播放的本地歌曲的序号
     */
    public void updatePlayingPosition() {
        int position = 0;
        long id = MusicSpUtils.getInstance(MusicConstant.SP_NAME).getLong(MusicConstant.MUSIC_ID, -1);
        if (audioMusics.isEmpty()) {
            return;
        }
        for (int index = 0; index < audioMusics.size(); index++) {
            String musicId = audioMusics.get(index).getId();
            MusicLogUtils.e("PlayService" + "----musicId----" + musicId);
            if (Long.parseLong(musicId) == id) {
                position = index;
                break;
            }
        }
        mPlayingPosition = position;
        long musicId = Long.parseLong(audioMusics.get(mPlayingPosition).getId());
        MusicSpUtils.getInstance(MusicConstant.SP_NAME).put(MusicConstant.MUSIC_ID, musicId);
    }

    /**
     * 获取播放进度监听器对象
     *
     * @return OnPlayerEventListener对象
     */
    public OnPlayerEventListener getOnPlayEventListener() {
        return mListener;
    }

    /**
     * 设置播放进度监听器
     *
     * @param listener listener
     */
    public void setOnPlayEventListener(OnPlayerEventListener listener) {
        mListener = listener;
    }

    /**-------------------------------------添加锁屏界面----------------------------------------*/

    /**
     * 打开锁屏页面，这块伤透了脑筋
     * 不管是播放状态是哪一个，只要屏幕灭了到亮了，就展现这个锁屏页面
     * 有些APP限制了状态，比如只有播放时才走这个逻辑
     */
    private void startLockAudioActivity() {
        /*
        * if (!mIsLocked && isPlaying()) {
        }*/
    }

    /**-------------------------------------播放list----------------------------------------*/
}
